package main

import (
	"github.com/gin-gonic/gin"
	pb "go_gprc/server/proto"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"log"
	"net/http"
	"strconv"
)

var grpcClient pb.UserServiceClient

type Response struct {
	Code int `json:"code"`

	Data interface{} `json:"data"`

	Msg string `json:"msg"`
}

func initGrpcClient() {
	conn, err := grpc.NewClient(":50055", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	grpcClient = pb.NewUserServiceClient(conn)
}

func handleListUsers(c *gin.Context) {
	pageStr := c.Query("page")
	pageSizeStr := c.Query("pageSize")

	if pageStr == "" || pageSizeStr == "" {
		c.JSON(http.StatusBadRequest, Response{
			Code: 400,
			Data: nil,
			Msg:  "page and pagesize params are required",
		})
		return
	}

	page, errPage := strconv.Atoi(pageStr)
	pageSize, errPageSize := strconv.Atoi(pageSizeStr)

	if errPage != nil {
		c.JSON(http.StatusBadRequest, Response{
			Code: 400,
			Data: nil,
			Msg:  "page param should be an integer",
		})
		return
	}

	if errPageSize != nil {
		c.JSON(http.StatusBadRequest, Response{
			Code: 400,
			Data: nil,
			Msg:  "pagesize param should be an integer",
		})
		return
	}

	req := &pb.ListUsersRequest{
		Page:     int32(page),
		PageSize: int32(pageSize),
	}

	resp, err := grpcClient.ListUsers(c, req)

	if err != nil {
		c.JSON(http.StatusInternalServerError, Response{
			Code: 500,
			Data: nil,
			Msg:  "InternalServerError",
		})
		return
	}

	c.JSON(http.StatusOK, Response{
		Code: 200,
		Data: resp,
		Msg:  "success",
	})
}

func handleDeleteUser(c *gin.Context) {

	id := c.Param("id")
	if _, err := strconv.Atoi(id); err != nil {
		c.JSON(http.StatusBadRequest, Response{
			Code: 400,
			Data: nil,
			Msg:  "ID should be an integer, not a string",
		})
		return
	}
	var req pb.DeleteUserRequest
	req.Id = id
	resp, err := grpcClient.DeleteUser(c, &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, Response{
			Code: 500,
			Data: nil,
			Msg:  "InternalServerError",
		})
		return
	}
	c.JSON(http.StatusOK, Response{
		Code: 200,
		Data: resp,
		Msg:  "success",
	})

}

func handleUpdateUser(c *gin.Context) {

	id := c.Param("id")

	if _, err := strconv.Atoi(id); err != nil {
		c.JSON(http.StatusInternalServerError, Response{
			Code: 500,
			Data: nil,
			Msg:  "ID should be an integer, not a string",
		})
		return
	}

	var req pb.UpdateUserRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusInternalServerError, Response{
			Code: 500,
			Data: nil,
			Msg:  "InternalServerError",
		})
		return
	}

	req.Id = id
	resp, err := grpcClient.UpdateUser(c, &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, Response{
			Code: 500,
			Data: nil,
			Msg:  "InternalServerError",
		})
		return
	}

	c.JSON(http.StatusOK, Response{
		Code: 200,
		Data: resp,
		Msg:  "success",
	})
}

func handleGetUser(c *gin.Context) {

	id := c.Param("id")

	if _, err := strconv.Atoi(id); err != nil {
		c.JSON(http.StatusInternalServerError, Response{
			Code: 500,
			Data: nil,
			Msg:  "ID should be an integer, not a string",
		})

		return
	}
	req := &pb.GetUserRequest{Id: id}
	resp, err := grpcClient.GetUser(c, req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, Response{
			Code: 500,
			Data: nil,
			Msg:  "InternalServerError",
		})
		return
	}
	c.JSON(http.StatusOK, Response{
		Code: 200,
		Data: resp,
		Msg:  "success",
	})

}

func handleCreateUser(c *gin.Context) {

	var req pb.CreateUserRequest

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusInternalServerError, Response{
			Code: 500,
			Data: nil,
			Msg:  "InternalServerError",
		})
		return
	}
	resp, err := grpcClient.CreateUser(c, &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, Response{
			Code: 500,
			Data: nil,
			Msg:  "InternalServerError",
		})
		return
	}
	c.JSON(http.StatusOK, Response{
		Code: 200,
		Data: resp,
		Msg:  "success",
	})

}

func main() {
	initGrpcClient()

	router := gin.Default()

	userGroup := router.Group("/users")
	{
		userGroup.GET("/", handleListUsers)

		userGroup.POST("/", handleCreateUser)

		userGroup.GET("/:id", handleGetUser)

		userGroup.PUT("/:id", handleUpdateUser)

		userGroup.DELETE("/:id", handleDeleteUser)
	}
	err := router.Run(":8080")
	if err != nil {

		log.Fatalf("init db failed, err: %v", err)

		return
	}
}
